package com.xr.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.mail.*;
import javax.mail.internet.*;
import java.io.IOException;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 邮件工具类，处理自定义邮件，附件发送等
 */
public class EmailUtils {

  private static final Logger logger = LoggerFactory.getLogger(EmailUtils.class);

  private static final String ACCOUNT = "";
  private static final String PASSWORD = "";

  private static Transport transport = null;
  private static Message message = null;

  static {
    Properties props = new Properties();
    props.setProperty("mail.smtp.auth", "true");
    props.setProperty("mail.host", "smtp.exmail.qq.com");
    props.setProperty("mail.transport.protocol", "smtp");
    props.setProperty("mail.smtp.port", "25");

    Session session = Session.getInstance(props, new Authenticator() {
      @Override
      protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(ACCOUNT, PASSWORD);
      }
    });

    try {
      session.setDebug(false);

      transport =  session.getTransport(new InternetAddress(MimeUtility.encodeText("reminder") + '<' + ACCOUNT + '>'));

      message = new MimeMessage(session);
      message.setFrom(new InternetAddress(ACCOUNT));
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage());
    }
  }

  /**
   * 发送邮件
   * @throws MessagingException
   * @throws IOException
   */
  private static void send(MailData mailData) throws MessagingException, IOException {
    message.setSubject(mailData.subject);
    message.setRecipients(Message.RecipientType.TO, toAddress(mailData.to));
    message.setRecipients(Message.RecipientType.CC, toAddress(mailData.cc));

    if (StringUtil.isEmpty(mailData.attachfile)) {
      message.setContent( mailData.content, "text/html;charset=utf-8");
    } else {
      Multipart part = new MimeMultipart();
      MimeBodyPart txtPart  = new MimeBodyPart();
      txtPart.setContent( mailData.content, "text/html;charset=utf-8");
      part.addBodyPart(txtPart);
      // 附件
      MimeBodyPart filePart = new MimeBodyPart();
      filePart.attachFile( mailData.attachfile );
      part.addBodyPart(filePart);
      message.setContent(part);
    }

    transport.connect();
    transport.send(message);
    transport.close();
  }

  // 解决多线程问题，由于共享的message
  private static Lock lock = new ReentrantLock();

  /**
   * 邮件发送
   *
   * @param mailData
   * @return boolean
   */
  public static boolean sendMail(MailData mailData) {
    lock.lock();
    try {
      send(mailData);
      return true;
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      lock.unlock();
    }
    return false;
  }

  /**
   * 异步发送mail
   *
   * @param mailData
   */
  public static void asynMail(final MailData mailData) {
    new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          EmailUtils.sendMail(mailData);
        } catch (Exception e) {
          Thread.currentThread().interrupt();
        }
      }
    }).start();
  }

  /**
   * 将邮件地址转换
   *
   * @param emails
   * @return Address[]
   */
  private static Address[] toAddress(String... emails) {
    if (CollectionUtil.isEmpty(emails)) {
      return null;
    }
    // 过滤非正常的email
    Set<Address> addSet = new HashSet<Address>();
    for (String email : emails) {
      boolean result = RegexUtils.match(RegexUtils.EMAIL, email);
      if (!result) {
        continue;
      }
      try {
        addSet.add(new InternetAddress(email));
      } catch (AddressException e) {
        continue;
      }
    }
    return addSet.toArray(new Address[0]);
  }

  /**
   * 邮件数据的封装
   */
  public static class MailData {
    // 发送给
    private String[] to = null;
    // 抄送
    private String[] cc = null;
    // 主题
    private String subject = null;
    // 内容
    private String content = null;
    // 附件
    private String attachfile = null;

    private MailData() {
    }

    public static MailData New() {
      return new MailData();
    }

    public MailData to(String... toEmails) {
      this.to = toEmails;
      return this;
    }

    public MailData cc(String... ccEmails) {
      this.cc = ccEmails;
      return this;
    }

    public MailData subject(String subject) {
      this.subject = subject;
      return this;
    }

    public MailData content(String content) {
      this.content = content;
      return this;
    }

    public MailData file(String filePath) {
      this.attachfile = filePath;
      return this;
    }
  }

}
